package com.nts.pmchelperdemo3.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.nts.pmchelperdemo3.constant.MessageConstant;
import com.nts.pmchelperdemo3.dto.MachineLoadDTO;
import com.nts.pmchelperdemo3.entity.Machine;
import com.nts.pmchelperdemo3.entity.Scheduling;
import com.nts.pmchelperdemo3.exception.MachineNullException;
import com.nts.pmchelperdemo3.mapper.MachineMapper;
import com.nts.pmchelperdemo3.mapper.SchedulingMapper;
import com.nts.pmchelperdemo3.service.MachineService;
import com.nts.pmchelperdemo3.service.SchedulingService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class MachineServiceImpl implements MachineService {
    @Autowired
    private MachineMapper machineMapper ;

    @Autowired
    private SchedulingMapper schedulingMapper;

    @Override
    public List<MachineLoadDTO> getAllMachines(Integer machineType)
    {
        QueryWrapper<Machine>queryWrapper = new QueryWrapper<>();
        if (machineType != null)
        {
            queryWrapper.eq("machine_type",machineType);
        }
        List<Machine> machines = machineMapper.selectList(queryWrapper);
        return machines.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    public MachineLoadDTO getMachineDeadline(String machineName)
    {
        QueryWrapper<Machine>queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("machine_name",machineName);
        Machine machine = machineMapper.selectOne(queryWrapper);
        if (machine == null)
        {
            throw new MachineNullException(MessageConstant.MACHINE_IS_NULL);
        }
        return convertToDTO(machine);
    }

    @Override
    public List<MachineLoadDTO>getMachineLoadByType(){
        List<Machine>allMachines = machineMapper.selectList(null);
        return allMachines.stream().collect(Collectors.groupingBy(Machine::getMachineType)).entrySet().stream().map(entry->{
            Integer type = entry.getKey();
            List<Machine>machines = entry.getValue();
            MachineLoadDTO dto = new MachineLoadDTO();
            dto.setMachineType(type);
            dto.setTypeName(type == 0 ? "磨刀机" : "涂层机");
            dto.setTotalCount(machines.size());
            //计算结束日期
            LocalDateTime latestDeadline = machines.stream().map(Machine::getCurrentScheduleEndTime).max(LocalDateTime::compareTo).orElse(LocalDateTime.now());
            dto.setCurrentDeadline(latestDeadline.toString());
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public List<Machine>getAvailableMachinesByType(Integer machineType){
        QueryWrapper<Machine>queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("machine_type",machineType);
        return machineMapper.selectList(queryWrapper);
    }

    @Override
    @Transactional
    public void updateMachineDeadline(Long machineId,String newEndTime){
        Machine machine = machineMapper.selectById(machineId);
        if (machine == null){
            throw new MachineNullException(MessageConstant.MACHINE_IS_NULL);
        }
        machine.setCurrentScheduleEndTime(LocalDateTime.parse(newEndTime));
        machineMapper.updateById(machine);
    }

    @Override
    public int countAvailableMachine(){
        return machineMapper.selectCount(null);
    }

    @Override
    public void resetMachineDeadlineIfNeeded(Long machineId, LocalDateTime taskEndTime) {
        Machine machine = machineMapper.selectById(machineId);
        if (machine == null){
            return;
        }

        if (machine.getCurrentScheduleEndTime() != null && machine.getCurrentScheduleEndTime().equals(taskEndTime)){
            QueryWrapper<Scheduling> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("machine_id", machineId)
                    .ge("task_start_time", LocalDateTime.now())
                    .orderByDesc("task_end_time");

            List<Scheduling> remainingSchedulings = schedulingMapper.selectList(queryWrapper);
            if (remainingSchedulings.isEmpty()) {
                machine.setCurrentScheduleEndTime(null);
            } else {
                machine.setCurrentScheduleEndTime(remainingSchedulings.get(0).getTaskEndTime());
            }

            machineMapper.updateById(machine);
        }
    }

    @Override
    public LocalDateTime regetTaskEndTime(Long machineId){
        QueryWrapper<Scheduling>queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("machine_id",machineId)
                .orderByDesc("task_end_time")
                .last("LIMIT 1");

        Scheduling latestTask = schedulingMapper.selectOne(queryWrapper);
        return latestTask != null ? latestTask.getTaskEndTime() : null;
    }

    private MachineLoadDTO convertToDTO(Machine machine){
        MachineLoadDTO dto = new MachineLoadDTO();
        BeanUtils.copyProperties(machine,dto);
        dto.setTypeName(machine.getMachineType() == 0 ? "磨刀机" : "涂层机");
        //若没排班，截止日期变为当前时间
        LocalDateTime deadline = machine.getCurrentScheduleEndTime() != null ? machine.getCurrentScheduleEndTime() : LocalDateTime.now();
        dto.setCurrentDeadline(deadline.toString());
        return dto;
    }

}
